#if !defined(PYTHON_DUMP_H)
#define PYTHON_DUMP_H


#include <boost/spirit/include/karma.hpp>


namespace python_dump
{
    namespace karma = boost::spirit::karma;
    using std::string;
    using std::vector;


    //8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
    // 
    //      Python dump functions
    // 
    //8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
    //________________________________________________________________________________________
    // 
    //  python_dump_bytes 
    // 
    //________________________________________________________________________________________
    template <typename OutputIterator, typename Container>
    bool python_dump_bytes(OutputIterator& sink, Container const& v)
    {
        using boost::spirit::karma::byte_;
        using boost::spirit::karma::dword;
        using boost::spirit::karma::generate;
    
        return generate(sink,
            's' << dword << *byte_,         // the grammar
            v.size(), v                     // the data to output 
        );
    }
    
    
    
    //________________________________________________________________________________________
    // 
    //  python_dump_string
    // 
    //________________________________________________________________________________________
    template <typename OutputIterator>
    bool python_dump_string(OutputIterator& sink, const string& str)
    {
        using boost::spirit::karma::dword;
        using boost::spirit::karma::generate;
        using boost::spirit::karma::string;
    
        return generate(sink,
                's' << dword << string,         // the grammar
            str.length(), str                     // the data to output 
        );
    }
    
    //________________________________________________________________________________________
    // 
    //  python_dump_long
    // 
    //________________________________________________________________________________________
    template <typename OutputIterator>
    bool python_dump_long(OutputIterator& sink, const int& value)
    {
        using boost::spirit::karma::dword;
        using boost::spirit::karma::generate;
        using boost::spirit::karma::int_;
    
        return generate(sink,
                        'i' << dword,         // the grammar
                        value                // the data to output 
        );
    }
    
    //________________________________________________________________________________________
    // 
    //  python_dump_vec_str
    // 
    //________________________________________________________________________________________
    template <typename OutputIterator>
    bool python_dump_vec_str(OutputIterator& sink, const vector<string>& strings)
    {
        using boost::spirit::karma::dword;
        using boost::spirit::karma::generate;
        using boost::spirit::karma::string;
    
        if (!generate(sink, '[' << dword, strings.size()))
            return false;
        for (unsigned i = 0; i < strings.size(); ++i)
            if (!python_dump_string(sink, strings[i]))
                return false;
        return true;
    }

};


// s\x05\x00\x00\x00

//

//  "s" followed by number of values, followed by list of bytes

//  array('h', [-1,1,0,-128,127,0])
// 's\x0c\x00\x00\x00
//    \xff\xff
//    \x01\x00
//    \x00\x00
//    \x80\xff
//    \x7f\x00
//    \x00\x00


//    * i (TYPE_INT) -- Represents a int on a 32-bit machine. Stored as an int32.
//    * I (TYPE_INT64) -- Represents a int on a 64-bit machine. Stored as an int64. When read on a 32-bit machine, this may automatically become a long (if it's above 2**31).
//    * f (TYPE_FLOAT) -- Represents a float in the old (< 1) marshal format. Stored as a string with a uint8 before it indicating the size.
//    * g (TYPE_BINARY_FLOAT) -- Represents a float in the new marshal format. Stored as a float64. (Thanks to Trevor Blackwell for noting that these are not float32 (along with TYPE_BINARY_COMPLEX).)
//    * x (TYPE_COMPLEX) -- Represents a complex in the old (< 1) marshal format. Contains the real and imaginary components stored like TYPE_FLOAT; that is, as strings.
//    * y (TYPE_BINARY_COMPLEX) -- Represents a complex in the new marshal format. Stored as two float64s representing the real and imaginary components.
//    * l (TYPE_LONG) -- Represents a long. Haven't yet figured out how this works; I'll update shortly with that.
//
//Strings
//
//    * s (TYPE_STRING) -- Represents a str. Stored as a int32 representing the size, followed by that many bytes.
//    * t (TYPE_INTERNED) -- Represents a str. Identical to TYPE_STRING, with the exception that it's added to an "interned" list as well.
//    * R (TYPE_STRINGREF) -- Represents a str. Stored as a int32 reference into the interned list mentioned above. Note that this is zero-indexed.
//    * u (TYPE_UNICODE) -- Represents a unicode. Stored as a int32 representing the size, followed by that many bytes. This is always UTF-8.
//
//Collections
//
//    * ( (TYPE_TUPLE) -- Represents a tuple. Stored as a int32 followed by that many objects, which are marshalled as well.
//    * [ (TYPE_LIST) -- Represents a list. Stored identically to TYPE_TUPLE.
//    * { (TYPE_DICT) -- Represents a dict. Stored as a series of marshalled key-value pairs. At the end of the dict, you'll have a "key" that consists of a TYPE_NULL; there's no value following it.
//    * < (TYPE_SET) -- Represents a set. Stored identically to TYPE_TUPLE.
//    * > (TYPE_FROZENSET) -- Represents a frozenset. Stored identically to TYPE_TUPLE.


#endif	// PYTHON_DUMP_H
